The Bulletin Board (aka Message Boards)
#######################################
by Dupois (dupois@home.com)

IMPORTANT:  LINUX Users!!!!  I have no way of compiling under LINUX
            and one of the functions, MsgBoardMaintenance() - line 2133 of
            msgboard.cpp, has a couple NON-ANSI functions, namely:
                _findfirst()
                _findnext()
                _findclose()
            These functions do exist for DJGPP and EGCS ( I'm pretty sure )
            but they are OS specific so each implementation is slightly
            different.  Anyone with LINUX experience, please feel free to
            fix up that portion of the code.  I put comments around the
            area where I believe it will need to be #ifdef'd.
            Sorry for the inconvenience, Dupois.

Bulletin Boards are implemented (yippeee!).  First off, lets start with the
simple stuff.  There are two files:
        
        msgboard.h
        msgboard.cpp

which contain all the code needed to run the boards.  Basically all that had
to be added to UOX3.CPP was the a little bit of code to handle the bulletin
board message packet (0x71) and when a user double-clicked on a bulletin
board (ID 1E5E & 1E5F).  Now when a GM creates a bulletin board object,
players could start posting messages.  The bulletin board can be renamed, 
however only the first 20 characters of the name will be shown, the rest will
be truncated (more than 20 characters in the name will overrun the title area
of the board anyway).  When a player opens the board by double-clicking on it
the name will be displayed where it normally says "bulletin board".  If the
board is not renamed then the default of "bulletin board" is displayed.

Oh, for those of you who want to add a bulletin board to your shard and
don't have InsideUO here are the commands to add one:

    /add 1e 5e                  board facing south  \
    /add 1e 5f                  board facing east   /

The boards work by creating two files per board by using the serial number for
the board as a file name.  I would highly recommend using the MSGBOARDPATH
setting in the SERVER.SCP file in order to keep all of the board files in one
location.

For example, if a bulletin board was added and its serial number (in hex)
was 40 00 00 19, then the files created would be as follows:
        
        40000019.bbi    Bulletin Board Index file
        40000019.bbp    Bulletin Board Post file

There is a maximum of 128 posts that can be displayed on a message board
at any one time.  The reason for this is that the BUFFERSIZE for messages to
the client is currently set to 2560 and with the way items are added to the 
bulletin board, this works out to 128 messages (actually its 134, but I like
to play it safe and round down - see msgboard.h for the calulation).  This
means that you could have 128 global messages OR 128 regional messages OR 
128 local messages OR any combination that totals 128 messages.  Any messages
beyond the 128th post, will be not be displayed when the board is opened up
fresh (but they will exist).  For this reason, The good thing about this is
that global/regional messages have a higher priority than local/user messages.
The board add any global posts first, then any regional posts, and finally,
the local postings (if any).

Users can post on the board in exactly the same way that they would have on 
the OSI servers (All player posts are local to that particular board).
That's the basic functionality of the bulletin boards.  The enhanced features
are some extra commands that GM's can use.  These are:

        /GPOST          Saves the next message to be posted as a global post.
                        This means that every bulletin board in the world will
                        see the posting.  (global.bbi & global.bbp)

        /RPOST          Saves the next message to be posted as a regional post.
                        This means that every bulletin board within the region
                        where the message was posted will see the post.  The 
                        name of the file created with this type of post is the
                        name of the region where the bulletin board is
                        physically located. ( region10.bbi & region10.bbp )

        /LPOST          Saves the message as a post local to the specific
                        bulletin board the message was posted on
                        (DEFAULT for all users & GM's). Users can only post
                        this type of message.  These posts are  saved in the
                        format mention before (ie 40000019.bbi, etc.)

        /POST           Returns the current setting of the "posting mode" for
                        the GM.


In addition to these commands, there are a few SERVER.SCP settings that can be
used to configure the bulletin boards.  They are as follows:

        MSGBOARDPATH    Path where the files related to the bulletin boards are
                        stored.  (Example:  C:\UOX3\MSGBOARD\  ending backslash
                        is required)
                        DEFAULT = same directory as uox3.exe

        MSGPOSTACCESS   Sets whether users can post messages at all.  GM's can 
                        always post a message.
                        DEFAULT = 0 ONLY GM's can post
                                  1 everyone can post

        MSGPOSTREMOVE   Sets whether users can remove posts or not.  GM's can
                        always remove a post.
                        DEFAULT = 0 Only GM's can remove a post
                                  1 everyone can remove a post-not a good idea

        MSGRETENTION    Sets the number of days that the messages will be kept
                        before being removed automatically.
                        DEFAULT 30 Days
                        MAXIMUM 365 (This is a bit extreme anyway)


ESCORT QUEST SYSTEM
###################
There is also an escort quest system integrated with the bulletin boards.
Its still in its early stages, but it should work fairly well.  The escort
engine is enabled by creating spawners with:

        type == 125

That pretty much means that you could, if you wanted to, escort cows or
pigs or dragons for that matter.  As long as its a valid NPC.

It then uses the msgboard.scp file to determine (randomly, no choice here
right now) which discription to use as a posting message.  There are a 
number of replaceable parameters that can be used.  The point here is
to experiment with it to see exactly what "fits" the posting window.
You'll see what I mean when it happens :).  Basically, if a line overruns
the posting window, you get an elipse replacing the remainder of the line.
(elipse is ...).  Also, Zippy's new area spawner code was used to randomly
place the NPC's in a region around the spawner and not always in the same 
spot.  This is configurable by setting the MORE value of the spawner to a
 value for the region to spawn within.

  Example:  You want the spawner to spawn in a region 10x12 (X by Y)

                /setmore 0 0 a c

                The values are in HEX so don't do a /setmore 0 0 10 12
                because that will be a region 6 squares larger in both
                the X and Y directions.

To set the type of NPC to spawn and how often to spawn them, use the
/setmorexyz <NPC> <MinTime> <maxTime> command.

  Example:  You want to create escort NPC that are zombies (just for the
            hell of it:) and you want them to spawn between 5 and 10 minutes.
            
            /setmorexyz 13 5 10

Only a couple of settings from the NPC.SCP are modified in the code, these
are:

    NPCAI     = 0  If its set to anything else, the NPC may react to 
                   other worldly effects, like an evil NPC or something
                   so I set it to 0 in the code to prevent this from happening

    NPCWANDER = 0  This is obvious, We don't want the NPC wandering away.


To identify a region as a valid escort region destination, the REGIONS.SCP
file needs to have an 'ESCORTS 1' entry added for every region. If there is
no ESCORTS entry or its set to 'ESCORTS 0', then the region will not be used
as an escort destination.  Simple enough, isn't it?  Oh, one important thing
to note is that the NAME of a region is very important when describing where
the NPC wants to be escorted.  So it should be something meaningfull.  The
destination region is determined randomly from the list of available regions.
A question someone will probably ask, "can an escort quest be generated for
the same town where the NPC is created?".  And the answer is No, I check for
that and make sure a region other than the current one will be used as the
destination.

Here is an example of making Cove a valid escort region:

SECTION REGION 10
{
NAME the town of Cove
MIDILIST 16
ESCORTS 1  <---- Here's the flag to set this region as an escort destination
GUARDED 1
GUARDNUM 1000
GUARDNUM 1000
GUARDNUM 1000
GUARDNUM 1000
GUARDNUM 1000
GUARDNUM 1001
GUARDNUM 1001
GUARDNUM 1001
GUARDNUM 1001
GUARDNUM 1001
GUARDOWNER Lord British's
MAGICDAMAGE 0
MARK 1
GATE 1
RECALL 1
SNOWCHANCE 10
RAINCHANCE 25
X1 2205
Y1 1120
X2 2290
Y2 1245
}

If there are no regions defined with ESCORTS, then the escort spawners
(type 125) will not spawn anything.  There are a couple of settings in the
SERVER.SCP file for configuring the way escorts work:

      ESCORTACTIVE         Turn escort quests on or off entirely.

      ESCORTINITEXPIRE     Time in seconds after creating the NPC to remove
                           it if no one accepts the quest.

      ESCORTACTIVEEXPIRE   Time in seconds after a player accepts a quest
                           to remove the quest if it hasn't been completed
                           yet.

      ESCORTDONEEXPIRE     Time in seconds after a player completes a quest
                           that the NPC wanders freely around until it is
                           removed.

After the NPC is spawned and the message is posted on the bulletin board,
a player can approach the NPC and use two words to find out the particulars
of the quest, if any.  The two options are:

        Destination          Asks the NPC where they want to go.
        I will take thee     Player accepts the quest and away they go...

Once the NPC arrives at its destination, there is a 5% chance that no payment
will be given at all.  Otherwise the pay range is between 75 and 600 gold.
Fair enough until it becomes scripted.  After arriving at the destination,
the NPC switches to wander freely mode and will roam around until the
ESCORT_DONE_EXPIRE time is reached, at which point it will be deleted (they
will just vanish).

There is a new startup routine that is done now that the bulletin boards are
in place.  Its a maintenance routine that deletes all messages marked for 
deletion and then compresses the BBI and BBP files to save space as well
as re-index all of the messages.  It will also clean up any dangling quest
posts that are not related to any valid world object.  A dangling post can
occur if a CHAR/ITEM is spawned as a quest object which then creates a posted
message on the bulletin board.  If the world is not saved and the server 
crashes (yeah, I know, that never happens :), you would have a post on the 
bulletin board refering to an object that doesn't exist.  In order to get
around this problem, the maintenance looks at all of the messages in the
BBI files and every post that is a quest is checked against the WSC file
to make sure the CHAR/ITEM exists.  If it doesn't, then the post is deleted.

One other thing to note about the bulletin board maintenance is that the 
server is setup to run the maintenance after an automatic world save occurs
ONLY if no one is online at the time.  If anyone is online then the world
save will occur as normal but the bulletin board maintenance rounting will
not.

If any of this needs a little more explaination, please use my e-mail address
given at the top to get in touch with me.


Well, that's it. This can definetly be improved upon but its a start at least.
I'm sure there are a lot of things that people would like to have scripted
instead of hard coded for one.

Thanks,
Dupois
